﻿namespace Pub.Class
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    public class Where
    {
        private IList<SearchInfo> conditions = new List<SearchInfo>();

        public Where And(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 0));
            return this;
        }

        public Where And(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 0, where));
            return this;
        }

        public Where AndBegin(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 1));
            return this;
        }

        public Where AndBegin(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 1, where));
            return this;
        }

        public Where AndEnd(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 2));
            return this;
        }

        public Where AndEnd(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.And, fieldName, fieldValue, oper, 2, where));
            return this;
        }

        private string OperatorToStr(Operator oper)
        {
            switch (oper)
            {
                case Operator.Like:
                    return " like ";

                case Operator.Equal:
                    return " = ";

                case Operator.NotEqual:
                    return " <> ";

                case Operator.MoreThan:
                    return " > ";

                case Operator.LessThan:
                    return " < ";

                case Operator.MoreThanOrEqual:
                    return " >= ";

                case Operator.LessThanOrEqual:
                    return " <= ";

                case Operator.Between:
                    return " between ";

                case Operator.In:
                    return " in ";

                case Operator.And:
                    return " and ";

                case Operator.Or:
                    return " or ";
            }
            return "=";
        }

        public Where Or(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 0));
            return this;
        }

        public Where Or(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 0, where));
            return this;
        }

        public Where OrBegin(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 1));
            return this;
        }

        public Where OrBegin(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 1, where));
            return this;
        }

        public Where OrEnd(string fieldName, object fieldValue, Operator oper)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 2));
            return this;
        }

        public Where OrEnd(string fieldName, object fieldValue, Operator oper, bool where)
        {
            this.conditions.Add(new SearchInfo(Operator.Or, fieldName, fieldValue, oper, 2, where));
            return this;
        }

        public string ToSql()
        {
            StringBuilder builder = new StringBuilder();
            foreach (SearchInfo info in this.conditions)
            {
                if (!info.Where || !info.FieldValue.IsNull())
                {
                    if (info.Operator == Operator.Like)
                    {
                        builder.AppendFormat("{3}{0}{1}'{2}'{4}", new object[] { info.FieldName, this.OperatorToStr(info.Operator), info.FieldValue, this.OperatorToStr(info.AndOr) + ((info.Type == 1) ? "(" : ""), (info.Type == 2) ? ")" : "" });
                    }
                    else if ((info.Operator == Operator.In) || (info.Operator == Operator.Between))
                    {
                        builder.AppendFormat("{3}{0}{1}{2}", new object[] { info.FieldName, this.OperatorToStr(info.Operator), info.FieldValue + ((info.Type == 2) ? ")" : ""), this.OperatorToStr(info.AndOr) + ((info.Type == 1) ? "(" : "") });
                    }
                    else
                    {
                        builder.AppendFormat("{3}{0}{1}{2}", new object[] { info.FieldName, this.OperatorToStr(info.Operator), ValueToStr(info.FieldValue) + ((info.Type == 2) ? ")" : ""), this.OperatorToStr(info.AndOr) + ((info.Type == 1) ? "(" : "") });
                    }
                }
            }
            return builder.ToString().Trim();
        }

        public override string ToString()
        {
            return this.ToSql();
        }

        public static string ValueToStr(object value)
        {
            if (value.IsNull())
            {
                return string.Empty;
            }
            switch (value.GetType().ToString())
            {
                case "System.Int16":
                    return value.ToString();

                case "System.UInt16":
                    return value.ToString();

                case "System.Single":
                    return value.ToString();

                case "System.UInt32":
                    return value.ToString();

                case "System.Int32":
                    return value.ToString();

                case "System.UInt64":
                    return value.ToString();

                case "System.Int64":
                    return value.ToString();

                case "System.String":
                    return "'{0}'".FormatWith(value.ToString().SafeSql());

                case "System.Double":
                    return value.ToString();

                case "System.Decimal":
                    return value.ToString();

                case "System.Byte":
                    return value.ToString();

                case "System.Boolean":
                    if (value.ToBool())
                    {
                        return "1";
                    }
                    return "0";

                case "System.DateTime":
                    return "'{0}'".FormatWith(value.ToString());

                case "System.Guid":
                    return "'{0}'".FormatWith(value.ToString());
            }
            return value.ToString();
        }
    }
}

